1 ========================================================================
2 CONSOLE APPLICATION : CSNamedPipeClient Project Overview
3 ========================================================================
5 /////////////////////////////////////////////////////////////////////////////
8 Named pipe is a mechanism for one-way or duplex inter-process communication
9 between the pipe server and one or more pipe clients in the local machine or
10 across the computers in the intranet:
13 Client (GENERIC_WRITE) ---> Server (GENERIC_READ)
16 Client (GENERIC_READ) <--- Server (GENERIC_WRITE)
19 Client (GENERIC_READ or GENERIC_WRITE, or both) <-->
20 Server (GENERIC_READ and GENERIC_WRITE)
22 This code sample demonstrate two methods to use named pipe in Visual C#.
24 1. Use the System.IO.Pipes namespace
26 The System.IO.Pipes namespace contains types that provide a means for
27 interprocess communication through anonymous and/or named pipes.
28 http://msdn.microsoft.com/en-us/library/system.io.pipes.aspx
29 These classes make the programming of named pipe in .NET much easier and
30 safer than P/Invoking native APIs directly. However, the System.IO.Pipes
31 namespace is not available before .NET Framework 3.5. So, if you are
32 programming against .NET Framework 2.0, you have to P/Invoke native APIs
35 The sample code in SystemIONamedPipeClient.Run() uses the
36 Systen.IO.Pipes.NamedPipeClientStream class to connect to the named pipe
37 "\\.\pipe\SamplePipe" to perform message-based duplex communication. The
38 client then writes a message to the pipe and receives the response from the
41 2. P/Invoke the native APIs related to named pipe operations.
43 The .NET interop services make it possible to call native APIs related to
44 named pipe operations from .NET. The sample code in
45 NativeNamedPipeClient.Run() demonstrates calling CreateFile to connect to
46 the named pipe "\\.\pipe\SamplePipe" with the GENERIC_READ and
47 GENERIC_WRITE accesses, and calling WriteFile and ReadFile to write a
48 message to the pipe and receive the response from the pipe server. Please
49 note that if you are programming against .NET Framework 3.5 or any newer
50 releases of .NET Framework, it is safer and easier to use the types in the
51 System.IO.Pipes namespace to operate named pipes.
54 /////////////////////////////////////////////////////////////////////////////
57 The following steps walk through a demonstration of the named pipe sample.
59 Step1. After you successfully build the CSNamedPipeClient and
60 CSNamedPipeServer sample projects in Visual Studio 2008, you will get the
61 applications: CSNamedPipeClient.exe and CSNamedPipeServer.exe.
63 Step2. Run CSNamedPipeServer.exe in a command prompt to start up the server
64 end of the named pipe. If the command is "CSNamedPipeServer.exe", the pipe
65 server is created by the types in the System.IO.Pipes namespace. If the
66 command is "CSNamedPipeServer.exe -native", the pipe server is created by
67 P/Invoking the native APIs related to named pipe operations. In both cases,
68 the application outputs the following information in the command prompt if
69 the pipe is created successfully.
72 The named pipe (\\.\pipe\SamplePipe) is created.
73 Waiting for the client's connection...
75 Step3. Run CSNamedPipeClient.exe in another command prompt to start up the
76 client end of the named pipe. If the command is "CSNamedPipeClient.exe", the
77 client connects to the pipe by using the types in the System.IO.Pipes
78 namespace. If the command is "CSNamedPipeClient.exe -native", the client
79 connects to the pipe by P/Invoking the native APIs related to named pipe
80 operations. In both cases, the application should output the message below
81 in the command prompt when the client successfully connects to the named pipe.
84 The named pipe (\\.\pipe\SamplePipe) is connected.
86 In the meantime, the server application outputs this message to indicate that
87 the pipe is connected by a client.
92 Step4. The client attempts to write a message to the named pipe. You will see
93 the message below in the commond prompt running the client application.
96 Send 56 bytes to server: "Default request from client"
98 When the server application reads the message from the client, it prints:
101 Receive 56 bytes from client: "Default request from client"
103 Next, the server writes a response to the pipe.
106 Send 58 bytes to client: "Default response from server"
108 And the client receives the response:
111 Receive 58 bytes from server: "Default response from server"
113 The connection is disconnected and the pipe is closed after that.
116 /////////////////////////////////////////////////////////////////////////////
118 (The relationship between the current sample and the rest samples in
119 Microsoft All-In-One Code Framework http://1code.codeplex.com)
121 CSNamedPipeClient -> CSNamedPipeServer/VBNamedPipeServer/CppNamedPipeServer
122 CSNamedPipeClient is the client end of the named pipe. CSNamedPipeServer,
123 VBNamedPipeServer and CppNamedPipeServer can be the server ends that create
126 CSNamedPipeClient - VBNamedPipeClient - CppNamedPipeClient
127 CSNamedPipeClient, VBNamedPipeClient and CppNamedPipeServer are the same
128 named pipe client ends written in three different programming languages.
131 /////////////////////////////////////////////////////////////////////////////
134 A. Named pipe client by using the System.IO.Pipes namespace.
135 (SystemIONamedPipeClient.Run())
137 1. Create a NamedPipeClientStream object and specify the pipe server, name,
138 pipe direction, options, etc.
140 pipeClient = new NamedPipeClientStream(
141 Program.SERVER_NAME, // The server name
142 Program.PIPE_NAME, // The unique pipe name
143 PipeDirection.InOut, // The pipe is duplex
144 PipeOptions.None // No additional parameters
147 2. Connect to the named pipe by calling NamedPipeClientStream.Connect().
149 pipeClient.Connect(5000);
151 3. Set the read mode and the blocking mode of the named pipe. In this sample,
152 we set data to be read from the pipe as a stream of messages. This allows a
153 reading process to read varying-length messages precisely as sent by the
154 writing process. In this mode, you should not use StreamWriter to write the
155 pipe, or use StreamReader to read the pipe. You can read more about the
156 difference from http://go.microsoft.com/?linkid=9721786.
158 pipeClient.ReadMode = PipeTransmissionMode.Message;
160 4. Send a message to the pipe server and receive its response through
161 NamedPipeClientStream.Read and NamedPipeClientStream.Write. Because
162 pipeClient.ReadMode = PipeTransmissionMode.Message, you should not use
163 StreamWriter to write the pipe, or use StreamReader to read the pipe.
166 // Send a request from client to server
169 string message = Program.REQUEST_MESSAGE;
170 byte[] bRequest = Encoding.Unicode.GetBytes(message);
171 int cbRequest = bRequest.Length;
173 pipeClient.Write(bRequest, 0, cbRequest);
175 Console.WriteLine("Send {0} bytes to server: \"{1}\"",
176 cbRequest, message.TrimEnd('\0'));
179 // Receive a response from server.
184 byte[] bResponse = new byte[Program.BUFFER_SIZE];
185 int cbResponse = bResponse.Length, cbRead;
187 cbRead = pipeClient.Read(bResponse, 0, cbResponse);
189 // Unicode-encode the received byte array and trim all the
190 // '\0' characters at the end.
191 message = Encoding.Unicode.GetString(bResponse).TrimEnd('\0');
192 Console.WriteLine("Receive {0} bytes from server: \"{1}\"",
195 while (!pipeClient.IsMessageComplete);
197 5. Close the client end of the pipe by calling NamedPipeClientStream.Close().
201 -------------------------
203 B. Named pipe client by P/Invoke the native APIs related to named pipe
204 operations. (NativeNamedPipeClient.Run())
206 1. Try to connect to a named pipe by P/Invoking CreateFile and specifying the
207 target pipe server, name, desired access, etc.
209 hNamedPipe = NativeMethod.CreateFile(
210 Program.FULL_PIPE_NAME, // Pipe name
211 FileDesiredAccess.GENERIC_READ | // Read access
212 FileDesiredAccess.GENERIC_WRITE, // Write access
213 FileShareMode.Zero, // No sharing
214 null, // Default security attributes
215 FileCreationDisposition.OPEN_EXISTING, // Opens existing pipe
216 0, // Default attributes
217 IntPtr.Zero // No template file
220 If all pipe instances are busy, wait for 5 seconds and connect again.
222 if (!NativeMethod.WaitNamedPipe(Program.FULL_PIPE_NAME, 5000))
224 throw new Win32Exception();
227 2. Set the read mode and the blocking mode of the named pipe. In this sample,
228 we set data to be read from the pipe as a stream of messages.
230 PipeMode mode = PipeMode.PIPE_READMODE_MESSAGE;
231 if (!NativeMethod.SetNamedPipeHandleState(hNamedPipe, ref mode,
232 IntPtr.Zero, IntPtr.Zero))
234 throw new Win32Exception();
237 3. Send a message to the pipe server and receive its response by calling
238 the WriteFile and ReadFile functions.
241 // Send a request from client to server
244 string message = Program.REQUEST_MESSAGE;
245 byte[] bRequest = Encoding.Unicode.GetBytes(message);
246 int cbRequest = bRequest.Length, cbWritten;
248 if (!NativeMethod.WriteFile(
249 hNamedPipe, // Handle of the pipe
250 bRequest, // Message to be written
251 cbRequest, // Number of bytes to write
252 out cbWritten, // Number of bytes written
253 IntPtr.Zero // Not overlapped
256 throw new Win32Exception();
259 Console.WriteLine("Send {0} bytes to server: \"{1}\"",
260 cbWritten, message.TrimEnd('\0'));
263 // Receive a response from server.
266 bool finishRead = false;
269 byte[] bResponse = new byte[Program.BUFFER_SIZE];
270 int cbResponse = bResponse.Length, cbRead;
272 finishRead = NativeMethod.ReadFile(
273 hNamedPipe, // Handle of the pipe
274 bResponse, // Buffer to receive data
275 cbResponse, // Size of buffer in bytes
276 out cbRead, // Number of bytes read
277 IntPtr.Zero // Not overlapped
281 Marshal.GetLastWin32Error() != ERROR_MORE_DATA)
283 throw new Win32Exception();
286 // Unicode-encode the received byte array and trim all the
287 // '\0' characters at the end.
288 message = Encoding.Unicode.GetString(bResponse).TrimEnd('\0');
289 Console.WriteLine("Receive {0} bytes from server: \"{1}\"",
292 while (!finishRead); // Repeat loop if ERROR_MORE_DATA
299 /////////////////////////////////////////////////////////////////////////////
302 MSDN: System.IO.Pipes Namespace
303 http://msdn.microsoft.com/en-us/library/system.io.pipes.aspx
305 MSDN: NamedPipeClientStream
306 http://msdn.microsoft.com/en-us/library/system.io.pipes.namedpipeclientstream.aspx
308 How to: Use Named Pipes to Communicate Between Processes over a Network
309 http://msdn.microsoft.com/en-us/library/bb546085.aspx
311 Introducing Pipes [Justin Van Patten]
312 http://blogs.msdn.com/bclteam/archive/2006/12/07/introducing-pipes-justin-van-patten.aspx
315 /////////////////////////////////////////////////////////////////////////////